import * as Comlink from "comlink";
import * as chokidar from "chokidar";
import path from "path";
import { supportLocalMediaType } from "@/common/constant";
import debounce from "lodash.debounce";
import { parseLocalMusicItem } from "@/common/file-util";
import { setInternalData } from "@/common/media-util";

let watcher: chokidar.FSWatcher;

const addedMusicItems: IMusic.IMusicItem[] = [];
const removedFilePaths: string[] = [];

let _onAdd: (musicItems: IMusic.IMusicItem[]) => void;
let _onRemove: (filePaths: string[]) => void;

async function setupWatcher(initPaths?: string[]) {
    watcher = chokidar.watch(initPaths ?? [], {
        depth: 10,
        persistent: true,
        ignorePermissionErrors: true,
    });

    watcher.on("add", async (fp, stats) => {
        if (
            stats.isFile() &&
      supportLocalMediaType.some((postfix) => fp.endsWith(postfix))
        ) {
            const musicItem = await parseLocalMusicItem(fp);
            musicItem.$$localPath = fp;
            setInternalData<IMusic.IMusicItemInternalData>(
                musicItem,
                "downloadData",
                {
                    path: fp,
                    quality: "standard",
                },
            );
            addedMusicItems.push(musicItem);
            syncAddedMusic();
        }
    });

    watcher.on("unlink", (fp) => {
        if (supportLocalMediaType.some((postfix) => fp.endsWith(postfix))) {
            removedFilePaths.push(fp);
            syncRemovedFilePaths();
        }
    });
}

const syncAddedMusic = debounce(
    () => {
        const copyOfAddedMusicItems = [...addedMusicItems];
        addedMusicItems.length = 0;
        _onAdd?.(copyOfAddedMusicItems);
    },
    500,
    {
        leading: false,
        trailing: true,
    },
);

const syncRemovedFilePaths = debounce(
    () => {
        const copyOfRemovedFilePaths = [...removedFilePaths];
        removedFilePaths.length = 0;
        _onRemove?.(copyOfRemovedFilePaths);
    },
    500,
    {
        leading: false,
        trailing: true,
    },
);

async function changeWatchPath(addPaths?: string[], rmPaths?: string[]) {
    console.log(addPaths, rmPaths);
    try {
        if (addPaths?.length) {
            watcher.add(addPaths);
        }
        if (rmPaths?.length) {
            watcher.unwatch(rmPaths);
            /**
       * chokidar的bug: https://github.com/paulmillr/chokidar/issues/1027
       * unwatch之后重新watch不会触发文件更新
       */
            rmPaths.forEach((it) => {
                // @ts-ignore
                const watchedDirEntry = watcher._watched.get(it);
                if (watchedDirEntry) {
                    // 移除所有子节点的监听
                    watchedDirEntry._removeWatcher(
                        path.dirname(it),
                        path.basename(it),
                        true,
                    );
                }
                // watcher._watched.delete(it);
            });
        }
    // console.log("WATCH PATH CHANGED", addPaths, rmPaths, watcher);
    } catch (e) {
        console.log(e);
    }
}

async function onAdd(fn: (musicItems: IMusic.IMusicItem[]) => void) {
    _onAdd = fn;
}

async function onRemove(fn: (filePaths: string[]) => void) {
    _onRemove = fn;
}

Comlink.expose({
    setupWatcher,
    changeWatchPath,
    onAdd,
    onRemove,
});
